﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.IO;
using System.Globalization;
using System.Data;

namespace MulticastTV
{
    /// <summary>
    /// If plugin's name is xmltv(offline type), this parser is activated.
    /// </summary>
    class ParseXmltv
    {
        XPathDocument doc ;
        XPathNavigator nav ;
        bool initialized = false;
        CultureInfo culture = CultureInfo.CurrentCulture;

        bool tzchecked = false;
        string tz = "";

        public ParseXmltv()
        {
        }

        public bool Start()
        {
            if (!initialized ) 
            {
                string fileName = Properties.Settings.Default.XmltvFile;
                if (File.Exists(fileName))
                {
                    fileName = Properties.Settings.Default.XmltvFile;
                    try
                    {
                        doc = new XPathDocument(fileName);
                    }
                    catch
                    {
                        return false;
                    }
                    nav = doc.CreateNavigator();
                    initialized = true;
                    return true;
                }
                else return false;
            }
            else
                return true;
        }

        public void reload()
        {
            initialized = false;
            nav = null;
            doc = null;
            tzchecked = false;
            tz = "";
        }

        public List<string[]> Parse(string chanName, string chanid)
        {
             List<string[]> result = new List<string[]>();
             bool sort=false;
             if (Properties.Settings.Default.XmltvSortingNeeded)
                 sort = true;

            //datetime range
            DateTime now = DateTime.Now;
            DateTime pstart = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
            DateTime pstop = pstart.AddDays(1).AddHours(11).AddMinutes(59);
            
            XPathExpression expr;
            expr = nav.Compile("//programme[@channel='"+chanid+"']");
            XPathNodeIterator iterator = nav.Select(expr);

            while (iterator.MoveNext())
            {
                XPathNavigator nav2 = iterator.Current.Clone();
                //attributes
                //start.attribute
                DateTime start=DateTime.MinValue;
                string strstart="";

                if (nav2.HasAttributes)
                {
                    nav2.MoveToFirstAttribute();
                    do
                    {
                        if (nav2.Name == "start")
                        {
                            strstart = nav2.Value;
                            if (!tzchecked)
                            {
                                if (strstart.EndsWith("CET"))
                                    tz = "+01:00";
                                else if (strstart.EndsWith("CEST"))
                                    tz ="+01:00";
                                else if (strstart.EndsWith("GMT"))
                                    tz = "gmt";
                                else if (!strstart.EndsWith("0"))
                                    tz = "local";
                            }
                            if (tz == "")
                                start = DateTime.ParseExact(strstart.Substring(0, 18)+":"+strstart.Substring(18, 2), "yyyyMMddHHmmss zzz", culture,DateTimeStyles.None);
                            else if (tz == "local")
                                start = DateTime.ParseExact(strstart.Substring(0, 14), "yyyyMMddHHmmss", culture, DateTimeStyles.AssumeLocal);
                            else if (tz == "gmt")
                                start = DateTime.ParseExact(strstart.Substring(0, 14), "yyyyMMddHHmmss", culture, DateTimeStyles.AssumeUniversal);
                            else
                                start = DateTime.ParseExact(strstart.Substring(0, 14)+tz, "yyyyMMddHHmmsszzz", culture, DateTimeStyles.None);

                            break;
                        }
                    } while (nav2.MoveToNextAttribute());

                    if (start.CompareTo(pstart) > 0 && start.CompareTo(pstop) < 0)
                    {
                        nav2.MoveToParent();
                        
                        string[] data;
                        if (!sort)
                            data = new string[4] { "", "", "", "" };
                        else
                        {
                            data = new string[5] { "", "", "", "", start.ToString("yyyyMMddHHmm") };
                        }
                        
                        data[3] = "http://localhost/" +strstart + ";sep" + chanid + ";sep" + chanName; // start date + chanid for details
                        data[0] = start.ToString("HH:mm yyyy-MM-dd");

                        // Stop date is not supported yet !!!
                        // move to first child
                        
                        if (nav2.HasChildren)
                            nav2.MoveToFirstChild();
                        do
                        {
                            if (nav2.Name == "title")
                            {
                                data[1] = nav2.Value;
                            }
                            else if (nav2.Name == "category")
                            {
                                if (data[2] == "")
                                    data[2] = nav2.Value;
                                else
                                    data[2] = data[2] + ", " + nav2.Value;
                            }
                        } while (nav2.MoveToNext());

                        if (sort)
                            result.Sort(new XmltvCompare());
                        result.Add(data);
                    }
                }
            }
            return result;
        }

        public string[] ParseDetails(string href)
        { 
            //href starts with http://localhost/
            string[] result = new string[10] { "", "", "", "", "", "", "", "", "", "" };
            string[] data = href.Substring(17).Split(new string[] { ";sep" },StringSplitOptions.None);
            string chanid = data[1];
            string starttime = data[0];
            string channame = data[2];

            XPathExpression expr;
            expr = nav.Compile("//programme[@channel='" + chanid + "' and @start='"+starttime+"']");
            XPathNodeIterator iterator = nav.Select(expr);
            while (iterator.MoveNext())
            {
                XPathNavigator nav2 = iterator.Current.Clone();
                if (nav2.HasChildren)
                    nav2.MoveToFirstChild();
                else
                    break;
                result[3] = channame;
                do
                {
                    if (nav2.Name == "title")
                    {
                        result[0] = nav2.Value;
                    }
                    else if (nav2.Name == "date")
                    {
                        result[4] = nav2.Value;
                    }
                    else if (nav2.Name == "category")
                    {
                        if (result[1] == "")
                            result[1] = nav2.Value;
                        else
                            result[1] = result[1] + ", " + nav2.Value;
                    }
                    else if (nav2.Name == "actor")
                    {
                        if (result[7] != "")
                            result[7] = MLmessages.Actors + ": ";
                        if (result[8] == "")
                            result[8] = nav2.Value;
                        else
                            result[8] = result[8] + ", " + nav2.Value;
                    }
                    else if (nav2.Name == "director")
                    {
                        if (result[5] != "")
                            result[5] = MLmessages.Director + ": ";
                        if (result[6] == "")
                            result[6] = nav2.Value;
                        else
                            result[6] = result[6] + ", " + nav2.Value;
                    }
                    else if (nav2.Name == "desc")
                    {
                        result[2] = nav2.Value;
                    }

                } while (nav2.MoveToNext());
                
                break;
            }
            if (result[4] == "")
            {
                if (tz == "")
                    result[4] = DateTime.ParseExact(starttime.Substring(0, 18) + ":" + starttime.Substring(18, 2), "yyyyMMddHHmmss zzz", culture, DateTimeStyles.None).ToString("dd.MM.yyyy",culture);
                else if (tz == "local")
                    result[4] = DateTime.ParseExact(starttime.Substring(0, 14), "yyyyMMddHHmmss", culture, DateTimeStyles.AssumeLocal).ToString("dd.MM.yyyy", culture);
                else if (tz == "gmt")
                    result[4] = DateTime.ParseExact(starttime.Substring(0, 14), "yyyyMMddHHmmss", culture, DateTimeStyles.AssumeUniversal).ToString("dd.MM.yyyy", culture);
                else
                    result[4] = DateTime.ParseExact(starttime.Substring(0, 14) + tz, "yyyyMMddHHmmsszzz", culture, DateTimeStyles.None).ToString("dd.MM.yyyy", culture);
           }

            return result;
        }

        // ufff
        public void loadIds(DataTable dt, string file)
        {
            XmlTextReader reader = new XmlTextReader(file);
            while (reader.Read())
            {
             if (reader.NodeType == XmlNodeType.Element)
             {
                 if (reader.Name=="channel")
                     while (reader.MoveToNextAttribute()) // Read the attributes.
                     {
                         if (reader.Name == "id")
                         {
                             string id = reader.Value;
                             string name = "";
                             reader.MoveToElement();
                             while (reader.Read())
                             {
                                 if (reader.NodeType == XmlNodeType.Element && reader.Name == "display-name")
                                 {
                                     while (reader.Read())
                                     {
                                         if (reader.NodeType == XmlNodeType.Text)
                                         {
                                             name = reader.Value;
                                             // here we have finnaly id vs name
                                             foreach (DataRow dr2 in dt.Rows)
                                             {
                                                 if (dr2[0].ToString().ToUpper() == name.ToUpper())
                                                 {
                                                     dr2[1] = id;
                                                     break;
                                                 }
                                             }
                                             break;
                                         }
                                     }
                                     break;
                                 }
                             }
                             break;
                         }
                     }
                }
            }
        }
    }

    // Sort xmltv programmes by date
    class XmltvCompare : IComparer<string[]>
    {
        public int Compare(string[] a, string[] b)
        {
            int i = 1;
            if (a != null && b != null)
            {
                i = a[4].CompareTo(b[4]);
            }
            return i;
        }
    }
}
